package com.core.service.impl;

import com.common.constants.ShiroConstant;
import com.common.model.entity.SysUser;
import com.common.model.vo.SysUserVO;
import com.core.mapper.SysUserMapper;
import com.core.service.SysUserService;
import com.common.utils.JwtUtils;
import com.common.utils.MD5Utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
import java.util.Set;

/**
 * @author : 帅宏-coding
 * @version : 1.0
 */
@Slf4j
@Service
public class SysUserServiceImpl implements SysUserService {

  // 注入二级缓存管理器
  @Resource(name = "twoLevelCacheManager")
  private CacheManager twoLevelCacheManager;

  @Resource
  private SysUserMapper sysUserMapper;

  @Override
  public long userRegister(String userName, String userPassword, String confirmPassword) {
    // 原有注册逻辑不变（注册无需缓存，直接操作数据库）
    String encryptedPassword = MD5Utils.encrypt(userName, userPassword);
    SysUser sysUser = sysUserMapper.getUserByUserName(userName);
    if (!ObjectUtils.isEmpty(sysUser)) {
      throw new RuntimeException(userName + "该用户已存在,不能重复注册-service");
    }
    if (!Objects.equals(userPassword, confirmPassword)) {
      throw new RuntimeException("俩次输入的密码输入不一致-service");
    }
    SysUser newUser = new SysUser();
    newUser.setUserName(userName);
    newUser.setUserPassword(encryptedPassword);
    newUser.setStatus(1);
    newUser.setIsDeleted(0);
    long insert = sysUserMapper.insert(newUser);
    if (insert <= 0) {
      throw new RuntimeException("用户注册失败-service");
    }
    return insert;
  }

  @Override
  public SysUserVO userLogin(String userName, String userPassword, Integer isRememberMe, HttpServletRequest request) {
    // 1. 密码加密
    String encryptedPassword = MD5Utils.encrypt(userName, userPassword);
    UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userName, encryptedPassword);
    Subject subject = SecurityUtils.getSubject();
    if (isRememberMe != null && isRememberMe == 1) {
      usernamePasswordToken.setRememberMe(true);
    }

    // 2. Shiro认证
    try {
      subject.login(usernamePasswordToken);
    } catch (AuthenticationException e) {
      throw new AuthenticationException("用户名或密码错误-service");
    }

    // 3. 通过二级缓存获取用户信息（核心修改：使用无后缀缓存名称 + 纯业务键）
    // 3.1 获取用户缓存实例（缓存名称：无后缀的业务标识）
    Cache userCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_USER);
    // 3.2 缓存键：直接用userName（不再拼接前缀）
    String userCacheKey = userName;

    // 3.3 从二级缓存查询用户信息
    // ShiroConstant.CACHE_NAME_SYS_USER：：userName  ===> 作为redis的key
    Cache.ValueWrapper userCacheWrapper = userCache.get(userCacheKey);
    SysUser sysUser = null;
    if (userCacheWrapper != null) {
      sysUser = (SysUser) userCacheWrapper.get();
      log.info("SysUserServiceImpl ---> 从二级缓存获取用户信息：{}", sysUser);
    }

    // 3.4 缓存未命中，从数据库查询并写入二级缓存
    if (sysUser == null) {
      sysUser = sysUserMapper.getUserByUserName(userName);
      // 写入二级缓存（自动同步本地Caffeine和Redis）
      userCache.put(userCacheKey, sysUser);
      log.info("SysUserServiceImpl ---> 从数据库获取用户信息，并存入二级缓存：{}", sysUser);
    }

    // 4. 生成JWT令牌
    String jwt = JwtUtils.createJWT(userName, JwtUtils.SECRET);
    log.info("SysUserServiceImpl ---> 创建jwt令牌：{}", jwt);

    // 5. 组装返回结果
    SysUserVO sysUserVO = new SysUserVO();
    BeanUtils.copyProperties(sysUser, sysUserVO);
    sysUserVO.setToken(jwt);
    return sysUserVO;
  }

  @Override
  public SysUserVO getCurrentLoginUser(HttpServletRequest request) {
    // 1. 获取token并解析用户名
    String token = request.getHeader(JwtUtils.TOKEN_HEADER);
    if (StringUtils.isBlank(token)) {
      throw new AuthenticationException("当前用户请求没有携带token，请重新登录");
    }
    String userName = JwtUtils.getUserNameByToken(token);

    // 2. 通过二级缓存获取用户信息（核心修改）
    Cache userCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_USER);
    String userCacheKey = userName; // 纯业务键
    Cache.ValueWrapper userCacheWrapper = userCache.get(userCacheKey);

    SysUser sysUser = null;
    if (userCacheWrapper != null) {
      sysUser = (SysUser) userCacheWrapper.get();
      log.info("getCurrentLoginUser ---> 从二级缓存获取用户信息：{}", sysUser);
    } else {
      // 缓存未命中，从数据库查询并补全缓存
      sysUser = sysUserMapper.getUserByUserName(userName);
      userCache.put(userCacheKey, sysUser);
      log.info("getCurrentLoginUser ---> 二级缓存未命中，从数据库获取并写入缓存：{}", sysUser);
    }

    // 3. 组装返回结果
    SysUserVO sysUserVO = new SysUserVO();
    BeanUtils.copyProperties(sysUser, sysUserVO);
    return sysUserVO;
  }

  @Override
  public boolean isAdmin(HttpServletRequest request) {
    return false; // 可根据实际需求实现
  }

  @Override
  public boolean userLogout(String userName) {
    // 1. 获取各缓存实例（使用无后缀的缓存名称）
    Cache userCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_USER);
    Cache roleCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_ROLE);
    Cache permissionCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_PERMISSION);
    Cache sessionCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SESSION);
    Cache defaultCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_DEFAULT);

    // 2. 构建缓存键（纯业务键，无需拼接前缀）
    String cacheKey = userName;

    // 3. 清除二级缓存（自动同步清除本地Caffeine和Redis）
    userCache.evict(cacheKey);
    roleCache.evict(cacheKey);
    permissionCache.evict(cacheKey);
    sessionCache.evict(cacheKey);
    defaultCache.evict(cacheKey);

    log.info("userLogout ---> 清除用户[{}]的所有二级缓存", userName);
    return true;
  }

  @Override
  public SysUser getUserByUserName(String userName) {
    // 补充：查询用户时走二级缓存（核心修改）
    Cache userCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_USER);
    String userCacheKey = userName; // 纯业务键
    Cache.ValueWrapper wrapper = userCache.get(userCacheKey);
    if (wrapper != null) {
      return (SysUser) wrapper.get();
    }
    SysUser sysUser = sysUserMapper.getUserByUserName(userName);
    userCache.put(userCacheKey, sysUser);
    return sysUser;
  }

  @Override
  public Set<String> getRoleByUserName(String userName) {
    // 补充：查询角色时走二级缓存（核心修改）
    Cache roleCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_ROLE);
    String roleCacheKey = userName; // 纯业务键
    Cache.ValueWrapper wrapper = roleCache.get(roleCacheKey);
    if (wrapper != null) {
      return (Set<String>) wrapper.get();
    }
    Set<String> roles = sysUserMapper.getUserRoleByUserName(userName);
    roleCache.put(roleCacheKey, roles);
    return roles;
  }

  @Override
  public Set<String> getPermissionsByUserName(String userName) {
    // 补充：查询权限时走二级缓存（核心修改）
    Cache permissionCache = twoLevelCacheManager.getCache(ShiroConstant.CACHE_NAME_SYS_PERMISSION);
    String permissionCacheKey = userName; // 纯业务键
    Cache.ValueWrapper wrapper = permissionCache.get(permissionCacheKey);
    if (wrapper != null) {
      return (Set<String>) wrapper.get();
    }
    Set<String> permissions = sysUserMapper.getPermissionsByUsername(userName);
    permissionCache.put(permissionCacheKey, permissions);
    return permissions;
  }
}
